/**
 *********************************************************
 ** <h1>SFMLex - Simple and Fast Multimedia Library Extensions.</h1>
 ** SFMLex Copyright (C) 2008 Neil Johnson (neil@emailus.me.uk)
 **
 ** SFML - Simple and Fast Multimedia Library
 ** Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
 **
 ** This software is provided 'as-is', without any express or implied warranty.
 ** In no event will the authors be held liable for any damages arising from the use of this software.
 **
 ** Permission is granted to anyone to use this software for any purpose,
 ** including commercial applications, and to alter it and redistribute it freely,
 ** subject to the following restrictions:
 **
 ** 1. The origin of this software must not be misrepresented;
 **    you must not claim that you wrote the original software.
 **    If you use this software in a product, an acknowledgment
 **    in the product documentation would be appreciated but is not required.
 **
 ** 2. Altered source versions must be plainly marked as such,
 **    and must not be misrepresented as being the original software.
 **
 ** 3. This notice may not be removed or altered from any source distribution.
 **
 ************************************************************
 */
#include "c_ResourceMgr.h"
#include <string>
#include <iostream>
#include <assert.h>
#include "c_ImageResource.h"
#include "c_SpriteResource.h"
#include "c_SoundBufferResource.h"
#include "c_MusicResource.h"
#include "c_AnimSpriteResource.h"

namespace sfx
{

   c_ResourceMgr::c_ResourceMgr(void)
   {
      init();
   }

   c_ResourceMgr::c_ResourceMgr( std::string& ScriptName )
   {
      init();

      loadScript( ScriptName );
   }

   c_ResourceMgr::~c_ResourceMgr(void)
   {
      deleteResources();
   }
      
   void c_ResourceMgr::init( void )
   {
      m_GroupMap.clear();
      m_Resources.clear();
      m_NameMap.clear();
   }
   
   bool c_ResourceMgr::loadScript( const std::string& ScriptName )
   {
      
      loadScript( ScriptName, m_Resources );
      
      const int NumOfResources = m_Resources.size();
      std::cerr << "Fnd " << NumOfResources << " resources." << std::endl;
      
      for( std::list<c_Resource*>::iterator it = m_Resources.begin(); it != m_Resources.end();  )
      {
         c_Resource* Resource;
         Resource = *it;
         assert( Resource != 0 );
         
         std::cerr << "processing " << Resource->getName() << std::endl;

         if( m_NameMap.count( Resource->getName() ) )
         {
            std::cerr << "erase " << Resource->getName() << std::endl;
            delete Resource;
            it = m_Resources.erase( it );
         }
         else
         {
            //Add to list
            m_NameMap.insert( make_pair(Resource->getName(), Resource ) );

            //Add to Group look up
            m_GroupMap.insert( make_pair(Resource->getGroup(), Resource ) );

            ++it;
         }

      }

      return true;
   }

   bool c_ResourceMgr::loadScript( const std::string& ScriptName, std::list<c_Resource*>& NewResources )
   {
      bool Success = false;
      
      NewResources.clear();

      XMLNode Root=XMLNode::parseFile( ScriptName.c_str(), "script" );
      
      if( !Root.isEmpty() )
      {
         const int NumOfEntrys = Root.nChildNode();

         for( int Idx = 0; Idx < NumOfEntrys; Idx++ )
         {
            XMLNode Node = Root.getChildNode( Idx );

            std::string NodeName( Node.getName() );

            if( NodeName == "resource" )
            {
               c_Resource* Resource;
               Resource = createResource( Node );
               if( Resource != 0 )
               {

                  NewResources.push_back( Resource );
               }
            }

         }

         Success = true;
      }
      
      return Success;
   }
   
   
   c_Resource* c_ResourceMgr::createResource( XMLNode& ResourceNode )
   {
      //Step 1
      //Check check if this node has an attribute called 'type'
      const std::string ResourceType( ResourceNode.getAttribute( "type" ) );

      c_Resource* Resource;
      Resource = c_Resource::createResource( this, ResourceType );
      if( Resource != 0 )
      {
         const int ChildNodeCnt = ResourceNode.nChildNode();

         for( int Idx = 0; Idx < ChildNodeCnt; Idx++ )
         {
            XMLNode ParameterNode = ResourceNode.getChildNode( Idx );

            const std::string ParameterName  = ParameterNode.getName();
            const std::string ParameterValue = ParameterNode.getText();
            
            if( Resource->setParameter( ParameterName, ParameterValue ) != true )
            {
               std::cerr << "Unsupported Parameter " << ParameterName << "(" << ParameterValue << ")" << std::endl;
            }
 
         }

      }
      else
      {
         std::cerr << "Resource Type of \"" << ResourceType << "\" is unkown" << std::endl;
      }
      
      return Resource;
   }

   bool c_ResourceMgr::cacheGroup( const std::string& GroupName )
   {
      std::multimap< std::string, c_Resource* >::iterator it;

      for( it = m_GroupMap.find( GroupName ); it != m_GroupMap.end(); it++ )
      {
         c_Resource* Resource;
         Resource = it->second;
         
         Resource->cache();
      }
      
      return true;
   }
   
   
   bool c_ResourceMgr::purgeGroup( const std::string& GroupName )
   {
      std::multimap< std::string, c_Resource* >::iterator it;

      for( it = m_GroupMap.find( GroupName ); it != m_GroupMap.end(); it++ )
      {
         c_Resource* Resource;
         Resource = it->second;
         
         Resource->purge();
      }

      return true;
   }

   void c_ResourceMgr::deleteResources( void )
   {
      for( std::list<c_Resource*>::iterator it = m_Resources.begin(); it != m_Resources.end(); ++it )
      {
         c_Resource* Resource;
         Resource = *it;
         assert( Resource != 0 );

         delete Resource;
      }

      m_Resources.clear();
   }
   
   sf::Image* c_ResourceMgr::getImage( const std::string& ImageName )
   {
      sf::Image* Image;
      Image = 0;

      c_Resource* Resource;
      Resource = m_NameMap[ ImageName ];
      if( Resource )
      {
         c_ImageResource* ImageResource = dynamic_cast<c_ImageResource*>(Resource);
         if( ImageResource )
         {
            Image = ImageResource->getImage();
         }
      }
      
      return Image;
   }
   
   sf::Sprite* c_ResourceMgr::createSprite( const std::string& SpriteName )
   {
      sf::Sprite* Sprite;
      Sprite = 0;

      c_Resource* Resource;
      Resource = m_NameMap[ SpriteName ];
      if( Resource )
      {
         c_SpriteResource* SpriteResource = dynamic_cast<c_SpriteResource*>(Resource);
         if( SpriteResource )
         {
            Sprite = SpriteResource->createSprite();
         }
      }
      
      return Sprite;
   }

   bool c_ResourceMgr::freeSprite( const std::string& SpriteName, sf::Sprite* Sprite )
   {
      c_Resource* Resource;
      Resource = m_NameMap[ SpriteName ];
      if( Resource )
      {
         c_SpriteResource* SpriteResource = dynamic_cast<c_SpriteResource*>(Resource);
         if( SpriteResource )
         {
            return SpriteResource->freeSprite( Sprite );
         }
      }
      
      return false;
   }

   sf::SoundBuffer* c_ResourceMgr::getSoundBuffer( const std::string& Name )
   {
      sf::SoundBuffer* Buffer(0);
      
      c_Resource* Resource;
      Resource = m_NameMap[ Name ];
      if( Resource )
      {
         c_SoundBufferResource* SndBufferResource = dynamic_cast<c_SoundBufferResource*>(Resource);
         if( SndBufferResource )
         {
            Buffer = SndBufferResource->getBuffer();
         }
      }
      
      return Buffer;
   }
   
   sf::Music* c_ResourceMgr::getMusic( const std::string& Name )
   {
      sf::Music* Music(0);
      
      c_Resource* Resource;
      Resource = m_NameMap[ Name ];
      if( Resource )
      {
         c_MusicResource* MusicResource = dynamic_cast<c_MusicResource*>(Resource);
         if( MusicResource )
         {
            Music = MusicResource->getMusic();
         }
      }
      
      return Music;
   }
   
   c_AnimSprite* c_ResourceMgr::createAnimSprite( const std::string& AnimSpriteName )
   {
      c_AnimSprite* AnimSprite;
      AnimSprite = 0;

      c_Resource* Resource;
      Resource = m_NameMap[ AnimSpriteName ];
      if( Resource )
      {
         c_AnimSpriteResource* AnimSpriteResource = dynamic_cast<c_AnimSpriteResource*>(Resource);
         if( AnimSpriteResource )
         {
            AnimSprite = AnimSpriteResource->createAnimSprite();
         }
      }
      
      return AnimSprite;
   }

   bool c_ResourceMgr::freeAnimSprite( const std::string& AnimSpriteName, c_AnimSprite* AnimSprite )
   {
      c_Resource* Resource;
      Resource = m_NameMap[ AnimSpriteName ];
      if( Resource )
      {
         c_AnimSpriteResource* AnimSpriteResource = dynamic_cast<c_AnimSpriteResource*>(Resource);
         if( AnimSpriteResource )
         {
            return AnimSpriteResource->freeAnimSprite( AnimSprite );
         }
      }
      
      return false;
   }

}
